/**
 * 文件归档以及压缩
 * 解压缩
 */

const archiver = require('archiver');
import * as fs from 'fs';
import * as path from 'path';
import * as extract from '@huanjiesm/extractzip';
import * as cp from "child_process";
import * as os from "os";

/**
 * 文档数据类型
 */
export enum DocType {
    FILE = 1,
    DIRECTORY = 2,
    GLOB = 3,
    BUFFER = 4
}

/**
 * 文档路径以及类型组合
 */
export interface DocArguments {
    path: string | fs.ReadStream,
    type: DocType,
    filename?: string
}

/**
 * 压缩/解压缩
 */
export class FreeArchiver {

    private constructor() { }

    /**
     * 使用zip压缩数据
     * @param des 目标文件名
     * @param doc 需要添加到压缩中的文件(文件夹)
     * @return {Promise<any>}
     */
    static zip(des: string, docs: DocArguments[]) {
        return new Promise((resolve, reject) => {
            let output = fs.createWriteStream(des);
            let arch = archiver('zip');
            output.on('error', (error: any) => {
                reject(error);
            });
            output.on('close', () => {
                resolve();
            });
            arch.pipe(output);
            arch.on("error", (err: any) => {
                reject(err);
            });
            for (let i = 0; i < docs.length; i++) {
                let element = docs[i];
                switch (element.type) {
                    case DocType.FILE:
                        arch.file(<string>element.path, { name: path.basename(<string>element.path) });
                        break;
                    case DocType.DIRECTORY:
                        arch.directory(<string>element.path, element.filename);
                        break;
                    case DocType.GLOB:
                        arch.glob(<string>element.path);
                        break;
                    case DocType.BUFFER:
                        arch.append(element.path, { name: element.filename });
                        break;
                    default:
                        break;
                }
            }
            arch.finalize();
        });
    }

    /**
     * 解压缩zip文件
     * @param source zip文件路径
     * @param dest 目标文件夹
     */
    static unzip(source: string, dest: string) {
        return new Promise((resolve, reject) => {
            extract(source, { dir: dest }, function (err: any) {
                if (err) {
                    reject(err);
                    return;
                }
                resolve();
            });
        });
    }

    /**
     * 解压缩rar压缩包
     * @param source 压缩包路径
     * @param dest 解压结果目录
     */
    static unrar(source: string, dest: string) {
        return new Promise((resolve, reject) => {
            if (os.platform() === "linux") {
                try {
                    let cmdstr = path.join(__dirname, "../unrar") + " x " + source + " " + dest;
                    cp.execSync(cmdstr);
                    resolve();
                } catch (error) {
                    reject(error);
                }
            } else {
                let childTask = cp.fork(path.join(__dirname, "./nodeunrar.js"));
                if (childTask) {
                    // 子进程发生异常
                    childTask.on("error", () => {
                        reject("文件解压失败");
                    })
                    // 子进程退出
                    childTask.on("exit", (code) => {
                        if (code === 0) {
                            resolve();
                        }
                        reject("文件解压失败，进程异常退出：" + code);
                    })
                    // 发送消息，启动解压
                    childTask.send({
                        filepath: source,
                        despath: dest
                    });
                }
            }
        });
    }
}